package model

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"encoding/json"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"regexp"
	"strconv"
	"strings"
)

type FSEquip struct {
	ID              int        `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
	ProjectID       int        `gorm:"column:project_id" json:"project_id"` // 工程ID
	Name            string     `gorm:"column:name" json:"name" binding:"required,max=30"`
	Code1           string     `gorm:"column:code1" json:"code1"`                                             // 自动生成 00-50
	IP              string     `json:"ip" gorm:"column:ip" binding:"required,max=15"`                         // IP地址
	Port            int        `json:"port" gorm:"column:port" binding:"required"`                            // 端口
	RedundantEnable uint8      `json:"redundant_enable" gorm:"column:redundant_enable" binding:"gte=0,lte=1"` // 是否开启冗余模块
	RedundantIP     string     `json:"redundant_ip" gorm:"column:redundant_ip" binding:"max=15"`              // 冗余IP地址
	RedundantPort   int        `json:"redundant_port" gorm:"column:redundant_port"`                           // 冗余端口
	RedundantParam1 float64    `json:"redundant_param1" gorm:"column:redundant_param1"`                       // 冗余参数1
	RedundantParam2 float64    `json:"redundant_param2" gorm:"column:redundant_param2"`                       // 冗余参数2
	RedundantParam3 float64    `json:"redundant_param3" gorm:"column:redundant_param3"`                       // 冗余参数3
	RunningState    uint8      `gorm:"column:running_state" json:"running_state"`                             // 0.异常 1.正在启动 2.已启动 3.正在停止 4.已停止 5.正在重连 6.备用 7.备用
	IntEndian       string     `gorm:"int_endian" json:"int_endian"`
	FloatEndian     string     `gorm:"float_endian" json:"float_endian"`
	DS              *DataScale `gorm:"-" json:"ds"`

	Detail     string      `gorm:"column:detail" json:"detail"`
	Sort       int         `gorm:"column:sort" json:"sort"`                         // 排序
	SyncRate   int         `gorm:"column:sync_rate" json:"sync_rate"`               // 通讯频率(ms)
	Stage      uint8       `gorm:"column:stage" json:"stage"`                       // 0.组态阶段 1.运行阶段
	CreateTime *string     `gorm:"column:create_time" json:"create_time"`           // 添加时间
	UpdateTime *string     `gorm:"column:update_time" json:"update_time"`           // 修改时间
	Del        uint8       `gorm:"column:del" json:"del"`                           // 0. 1.删除
	FSModule   []*FSModule `json:"fs_module"  gorm:"foreignKey:FSID;references:ID"` // foreignKey 外表外键 references 当前表关联键

	TcpClient      *TCPClient `gorm:"-" json:"-"` // tcp 客户端
	ReconnectTimes int        `gorm:"-" json:"reconnect_times"`
	DSModuleRead   int64      `gorm:"-" json:"ds_module_read"` // 是否读取过 FS模块规模
	DSModelRead    int64      `gorm:"-" json:"ds_model_read"`  // 是否读取过 FS控制模型规模
	DSMatched      uint8      `gorm:"-" json:"ds_matched"`     // 数据规模是否匹配 0.不匹配 1.匹配 , 指令0602返回时验证, 验证通过则修改此值, 不通过则持续下载直至通过
}

type FSEquipSlim struct {
	ID        int    `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
	ProjectID int    `gorm:"column:project_id" json:"project_id"` // 工程ID
	Name      string `gorm:"column:name" json:"name" binding:"required,max=30"`
}

func (fse *FSEquip) TableName() string {
	return "fs_equip"
}
func (fse *FSEquipSlim) TableName() string {
	return "fs_equip"
}

func (fse *FSEquip) Exists(id int) (exist bool, err error) {
	err = DB.Where("id = ?", id).Limit(1).Find(fse).Error
	if err != nil {
		return
	}
	if fse.ID == 0 {
		return
	}
	exist = true
	return
}

type ModuleType struct {
	FSID       int         `json:"fs_id"`       // 自研设备FS ID
	ModuleType string      `json:"module_type"` // 模块类型
	ModuleNum  int         `json:"module_num"`  // 模块数量
	ChannelNum int         `json:"channel_num"` // 通道数量,变量数量
	List       []*FSModule `json:"list"`
}

type ModuleList struct {
	ID         int          `json:"id"`
	FSID       int          `json:"fs_id"`       // 自研设备FS ID
	ModuleType string       `json:"module_type"` // 模块类型
	ModuleName string       `json:"module_name"` // 模块名称
	Code3      string       `json:"code3"`
	ChannelNum int          `json:"channel_num"` // 通道数量,变量数量
	CreateTime *string      `gorm:"column:create_time" json:"create_time"`
	UpdateTime *string      `gorm:"column:update_time" json:"update_time"`
	List       []*FrameItem `json:"list"`
}

type FSModule struct {
	ID         int          `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
	Code1      string       `gorm:"column:code1" json:"code1"`           // 00-50
	Code2      string       `gorm:"column:code2" json:"code2"`           // 00-14
	Code3      string       `gorm:"column:code3" json:"code3"`           // 00-99 模块编号, 模型序号
	ProjectID  int          `gorm:"column:project_id" json:"project_id"` // 工程ID
	FSID       int          `gorm:"column:fs_id" json:"fs_id"`
	ModuleType string       `gorm:"column:module_type" json:"module_type"` // 模块类型 AI AQ DI DQ Other
	ModuleName string       `gorm:"column:module_name" json:"module_name"` // AI0 AI1 AI2 ...
	JsonDetail string       `gorm:"column:json_detail" json:"json_detail"` // 模型详细配置信息JSON格式
	CreateTime *string      `gorm:"column:create_time" json:"create_time"` // 添加时间
	UpdateTime *string      `gorm:"column:update_time" json:"update_time"` // 修改时间
	Del        int          `gorm:"column:del" json:"del"`                 // 0.1.删除
	FrameItem  []*FrameItem `json:"frame_item"  gorm:"foreignKey:ModuleID;references:ID"`
}

type FSModel struct {
	FSModule
	Content     interface{} `gorm:"-" json:"content"` // 解析后的模型数据
	FSName      string      `json:"fs_name" gorm:"-"`
	FSEquipInfo *FSEquip    `json:"fs_equip"  gorm:"foreignKey:FSID;references:ID"`
}

func (fsm *FSModule) Exists(id int) (exist bool, err error) {
	err = DB.Where("id = ?", id).Limit(1).Find(fsm).Error
	if err != nil {
		return
	}
	if fsm.ID == 0 {
		return
	}
	exist = true
	return
}

func (fsm *FSModule) TableName() string {
	return "fs_module"
}

type FSModuleExt struct {
	FSModule
	FSEInfo FSEquip `json:"fs_info"  gorm:"foreignKey:FSID;references:ID"`
}

func (fsm *FSModuleExt) TableName() string {
	return "fs_module"
}

func (fse *FSEquip) ValidateBase() (err error) {
	if !tools.IsValidIP(fse.IP) {
		return errors.New("无效的ip")
	}
	if fse.RedundantIP == "" {
		fse.RedundantIP = "127.0.0.1"
	}
	if !tools.IsValidIP(fse.RedundantIP) {
		return errors.New("无效的冗余ip")
	}
	if fse.Port != 0 {
		if fse.Port < 0 || fse.Port > 65535 {
			return errors.New("无效的端口")
		}
	}
	if fse.RedundantPort != 0 {
		if fse.RedundantPort < 0 || fse.RedundantPort > 65535 {
			return errors.New("无效的冗余端口")
		}
	}
	if !AllowEndian[fse.IntEndian] {
		return errors.New("无效的大小端")
	}
	if !AllowEndian[fse.FloatEndian] {
		return errors.New("无效的大小端")
	}
	if fse.SyncRate == 0 {
		fse.SyncRate = 1000
	}
	return nil
}

func (fse *FSEquip) UpdateRunningState(state uint8, detail string) (err error) {
	WSClientMap.BroadCastEquipRunningState("fse", fse.ID, int(state))
	updateData := make(map[string]interface{})
	updateData["running_state"] = state
	updateData["detail"] = detail
	err = DB.Model(&FSEquip{}).Where("id = ?", fse.ID).Updates(updateData).Error
	return
}

func (fse *FSEquip) UpdateVariablesMap() (err error) {
	for _, frame := range fse.FSModule {
		for _, row := range frame.FrameItem {
			v, ok := VariablesMap.Get(row.Addr)
			if ok {
				v.FrameItem = *row
			} else {
				variable := &Variable{
					FrameItem: *row,
				}
				VariablesMap.Set(row.Addr, variable)
			}
		}
	}
	return
}

func (fse *FSEquip) Write(data []byte) (n int, err error) {
	if fse.TcpClient == nil {
		err = errors.New("tcp client is nil")
		return
	}
	if fse.TcpClient.Connection == nil {
		err = errors.New("tcp client.connection is nil")
		return
	}
	n, err = fse.TcpClient.Connection.Write(data)
	return
}

func (fse *FSEquip) CalculateDataScale() {
	ds := &DataScale{}
	for _, module := range fse.FSModule {
		if module.ModuleType == "AI" {
			ds.AI++
		}
		if module.ModuleType == "AQ" {
			ds.AQ++
		}
		if module.ModuleType == "DI" {
			ds.DI++
		}
		if module.ModuleType == "DQ" {
			ds.DQ++
		}
		if module.ModuleType == "Other" {
			ds.Other++
		}
		if module.ModuleType == "泵组电磁阀" {
			ds.Bengzu++
		}
		if module.ModuleType == "增压泵电磁阀" {
			ds.Zengya++
		}
		if module.ModuleType == "电调阀" {
			ds.Diantiao++
		}
		if module.ModuleType == "压力电磁阀" {
			ds.Pressure++
		}
		if module.ModuleType == "电源控制" {
			ds.Power++
		}
		if module.ModuleType == "电源状态" {
			ds.PowerState++
		}
		if module.ModuleType == "模态采集" {
			ds.ModeCollect++
		}
		if module.ModuleType == "故障诊断" {
			ds.Diag++
		}
	}
	fse.DS = ds
}

func (fse *FSEquip) GetChannels(code2, code3 string) (list []*FrameItem) {
	//fmt.Printf("code2=%s , code3=%s\n", code2, code3)
	list = make([]*FrameItem, 0)
	for _, module := range fse.FSModule {
		if module.Code2 == code2 && module.Code3 == code3 {
			list = module.FrameItem
		}
	}
	return
}

// AllCode1 00 - 50
func AllCode1() (arr []string) {
	arr = make([]string, 0)
	for i := 0; i <= 50; i++ {
		arr = append(arr, fmt.Sprintf("%02d", i))
	}
	return
}

func AllCode2() (arr []string) {
	arr = make([]string, 0)
	for i := 0; i <= 99; i++ {
		arr = append(arr, fmt.Sprintf("%02d", i))
	}
	return
}

// AllCode3 获取 00 - 99
func AllCode3() (arr []string) {
	arr = make([]string, 0)
	for i := 0; i <= 99; i++ {
		arr = append(arr, fmt.Sprintf("%02d", i))
	}
	return
}
func AllCode3FS() (arr []string) {
	arr = make([]string, 0)
	for i := 1; i <= 99; i++ {
		arr = append(arr, fmt.Sprintf("%02d", i))
	}
	return
}

// AllCode4 获取 000 - 999
func AllCode4() (arr []string) {
	arr = make([]string, 0)
	for i := 0; i <= 999; i++ {
		arr = append(arr, fmt.Sprintf("%03d", i))
	}
	return
}
func AllCode4FS() (arr []string) {
	arr = make([]string, 0)
	for i := 1; i <= 999; i++ {
		arr = append(arr, fmt.Sprintf("%03d", i))
	}
	return
}
func GetAvailableCode(allCode []string, usedCode []string) (availableCode []string) {
	m1 := make(map[string]bool)
	for _, v := range usedCode {
		m1[v] = true
	}
	availableCode = make([]string, 0)
	for _, row := range allCode {
		if !m1[row] {
			availableCode = append(availableCode, row)
		}
	}
	return
}

/*------ FS自研设备模型数据结构 ------*/

// BengzuModel 泵组电磁阀模型
type BengzuModel struct {
	QianjibengStartControl string `json:"qianjibeng_start_control"` // 前级泵-启动控制
	QianjibengStopControl  string `json:"qianjibeng_stop_control"`  // 前级泵-停止控制
	QianjibengStartState   string `json:"qianjibeng_start_state"`   // 前级泵-启动状态
	QianjibengStopState    string `json:"qianjibeng_stop_state"`    // 前级泵-停止状态

	QianjibengStartControlEV uint8 `json:"qianjibeng_start_control_ev"` // 前级泵-启动控制-有效值  EV == effective value
	QianjibengStopControlEV  uint8 `json:"qianjibeng_stop_control_ev"`  // 前级泵-停止控制-有效值
	QianjibengStartStateEV   uint8 `json:"qianjibeng_start_state_ev"`   // 前级泵-启动状态-有效值
	QianjibengStopStateEV    uint8 `json:"qianjibeng_stop_state_ev"`    // 前级泵-停止状态-有效值

	LuocibengStartControl string `json:"luocibeng_start_control"` // 罗茨泵-启动控制
	LuocibengStopControl  string `json:"luocibeng_stop_control"`  // 罗茨泵-停止控制
	LuocibengStartState   string `json:"luocibeng_start_state"`   // 罗茨泵-启动状态
	LuocibengStopState    string `json:"luocibeng_stop_state"`    // 罗茨泵-停止状态

	LuocibengStartControlEV uint8 `json:"luocibeng_start_control_ev"` // 罗茨泵-启动控制-有效值
	LuocibengStopControlEV  uint8 `json:"luocibeng_stop_control_ev"`  // 罗茨泵-停止控制-有效值
	LuocibengStartStateEV   uint8 `json:"luocibeng_start_state_ev"`   // 罗茨泵-启动状态-有效值
	LuocibengStopStateEV    uint8 `json:"luocibeng_stop_state_ev"`    // 罗茨泵-停止状态-有效值

	BengqianStartControl string `json:"bengqian_start_control"` // 泵前电磁阀-启动控制
	BengqianStopControl  string `json:"bengqian_stop_control"`  // 泵前电磁阀-停止控制
	BengqianStartState   string `json:"bengqian_start_state"`   // 泵前电磁阀-启动状态
	BengqianStopState    string `json:"bengqian_stop_state"`    // 泵前电磁阀-停止状态

	BengqianStartControlEV uint8 `json:"bengqian_start_control_ev"` // 泵前电磁阀-启动控制-有效值
	BengqianStopControlEV  uint8 `json:"bengqian_stop_control_ev"`  // 泵前电磁阀-停止控制-有效值
	BengqianStartStateEV   uint8 `json:"bengqian_start_state_ev"`   // 泵前电磁阀-启动状态-有效值
	BengqianStopStateEV    uint8 `json:"bengqian_stop_state_ev"`    // 泵前电磁阀-停止状态-有效值

	BengqianPressure string `json:"bengqian_pressure"` // 泵前压力

	/*--- 以上都是选择的 AI~DQ 的通道变量地址 ---*/
	BengzuStartControl      string `json:"bengzu_start_control"` // 泵组控制-启动控制 00
	BengzuStartControlValue uint8  `json:"bengzu_start_control_value"`
	BengzuStopControl       string `json:"bengzu_stop_control"` // 泵组控制-停止控制 01
	BengzuStopControlValue  uint8  `json:"bengzu_stop_control_value"`
	BengzuStartState        string `json:"bengzu_start_state"` // 泵组控制-启动状态 02
	BengzuStartStateValue   uint8  `json:"bengzu_start_state_value"`
	BengzuStopState         string `json:"bengzu_stop_state"` // 泵组控制-停止状态 03
	BengzuStopStateValue    uint8  `json:"bengzu_stop_state_value"`

	BengzuStartControlEV uint8 `json:"bengzu_start_control_ev"` // 泵组控制-启动控制-有效值 00
	BengzuStopControlEV  uint8 `json:"bengzu_stop_control_ev"`  // 泵组控制-停止控制-有效值 01
	BengzuStartStateEV   uint8 `json:"bengzu_start_state_ev"`   // 泵组控制-启动状态-有效值 02
	BengzuStopStateEV    uint8 `json:"bengzu_stop_state_ev"`    // 泵组控制-停止状态-有效值 03

	BengzuParam1      string  `json:"bengzu_param1"` // 泵组控制-参数1 04
	BengzuParam1Value float64 `json:"bengzu_param1_value"`
	BengzuParam2      string  `json:"bengzu_param2"` // 泵组控制-参数2 05
	BengzuParam2Value float64 `json:"bengzu_param2_value"`
	BengzuParam3      string  `json:"bengzu_param3"` // 泵组控制-参数3 06
	BengzuParam3Value float64 `json:"bengzu_param3_value"`
	BengzuParam4      string  `json:"bengzu_param4"` // 泵组控制-参数4 07
	BengzuParam4Value float64 `json:"bengzu_param4_value"`
	BengzuParam5      string  `json:"bengzu_param5"` // 泵组控制-参数5 08
	BengzuParam5Value float64 `json:"bengzu_param5_value"`
	/*--- 以上都是自动生成的变量地址 ---*/
	Liansuo            string `json:"liansuo"` // 泵组控制-连锁 09
	LiansuoValue       uint8  `json:"liansuo_value"`
	RemoteLocal        string `json:"remote_local"` // 远程就地
	RemoteLocalValue   uint8  `json:"remote_local_value"`
	ControlMethod      string `json:"control_method"` // 泵组控制-控制方法 11
	ControlMethodValue uint8  `json:"control_method_value"`
}

// ZengyaModel 增压泵模型
type ZengyaModel struct {
	BengqianPressure string `json:"bengqian_pressure"` // 泵前压力

	BengqianStartControl string `json:"bengqian_start_control"` // 泵前电磁阀-启动控制
	BengqianStopControl  string `json:"bengqian_stop_control"`  // 泵前电磁阀-停止控制
	BengqianStartState   string `json:"bengqian_start_state"`   // 泵前电磁阀-启动状态
	BengqianStopState    string `json:"bengqian_stop_state"`    // 泵前电磁阀-停止状态

	BengqianStartControlEV uint8 `json:"bengqian_start_control_ev"` // 泵前电磁阀-启动控制-有效值
	BengqianStopControlEV  uint8 `json:"bengqian_stop_control_ev"`  // 泵前电磁阀-停止控制-有效值
	BengqianStartStateEV   uint8 `json:"bengqian_start_state_ev"`   // 泵前电磁阀-启动状态-有效值
	BengqianStopStateEV    uint8 `json:"bengqian_stop_state_ev"`    // 泵前电磁阀-停止状态-有效值

	ZengyaStartControl string `json:"zengya_start_control"` // 增压泵-启动控制
	ZengyaStopControl  string `json:"zengya_stop_control"`  // 增压泵-停止控制
	ZengyaStartState   string `json:"zengya_start_state"`   // 增压泵-启动状态
	ZengyaStopState    string `json:"zengya_stop_state"`    // 增压泵-停止状态

	ZengyaStartControlEV uint8 `json:"zengya_start_control_ev"` // 增压泵-启动控制-有效值
	ZengyaStopControlEV  uint8 `json:"zengya_stop_control_ev"`  // 增压泵-停止控制-有效值
	ZengyaStartStateEV   uint8 `json:"zengya_start_state_ev"`   // 增压泵-启动状态-有效值
	ZengyaStopStateEV    uint8 `json:"zengya_stop_state_ev"`    // 增压泵-停止状态-有效值
	/*--- 以上全部都是选择的 AI~DQ ---*/

	Liansuo            string `json:"liansuo"` // 连锁 00
	LiansuoValue       uint8  `json:"liansuo_value"`
	RemoteLocal        string `json:"remote_local"` // 远程/就地
	RemoteLocalValue   uint8  `json:"remote_local_value"`
	ControlMethod      string `json:"control_method"` // 控制方法 02
	ControlMethodValue uint8  `json:"control_method_value"`
}

// DiantiaoSVModel 电调阀模型
type DiantiaoSVModel struct {
	CurrentKaidu   string `json:"current_kaidu"`   // 当前开度
	SetKaidu       string `json:"set_kaidu"`       // 设置开度
	Control        string `json:"control"`         // 控制
	SetStep        string `json:"set_step"`        // 设置步长
	SelfInspection string `json:"self_inspection"` // 自检控制
	Up             string `json:"up"`              // 上调
	Down           string `json:"down"`            // 下调
	AllOn          string `json:"all_on"`          // 全开
	AllOff         string `json:"all_off"`         // 全关
	AllOnState     string `json:"all_on_state"`    // 全开状态
	AllOffState    string `json:"all_off_state"`   // 全关状态
	QianjiPressure string `json:"qianji_pressure"` // 前级压力
	HoujiPressure  string `json:"houji_pressure"`  // 后级压力
	DestPressure   string `json:"dest_pressure"`   // 目标压力
	P              string `json:"p"`               // P
	I              string `json:"i"`               // I
	D              string `json:"d"`               // D

	CustomStartControl string `json:"custom_start_control"` // 自整定-启动控制
	CustomStopControl  string `json:"custom_stop_control"`  // 自整定-停止控制
	CustomStartState   string `json:"custom_start_state"`   // 自整定-启动状态
	CustomStopState    string `json:"custom_stop_state"`    // 自整定-停止状态

	CustomStartControlEV uint8 `json:"custom_start_control_ev"` // 自整定-启动控制-有效值
	CustomStopControlEV  uint8 `json:"custom_stop_control_ev"`  // 自整定-停止控制-有效值
	CustomStartStateEV   uint8 `json:"custom_start_state_ev"`   // 自整定-启动状态-有效值
	CustomStopStateEV    uint8 `json:"custom_stop_state_ev"`    // 自整定-停止状态-有效值

	Custom        string `json:"custom"`         // 自整定
	PID           string `json:"pid"`            // PID
	RemoteLocal   string `json:"remote_local"`   // 远程/就地
	ControlMethod string `json:"control_method"` // 控制方法
	/*--- 以上全部都是选择的 AI~DQ ---*/
}

// PressureSVModel 压力电磁阀
type PressureSVModel struct {
	Pressure       string `json:"pressure"`         // 压力测点
	SVStartControl string `json:"sv_start_control"` // 电磁阀-开控制
	SVStopControl  string `json:"sv_stop_control"`  // 电磁阀-关控制
	SVStartState   string `json:"sv_start_state"`   // 电磁阀-开状态
	SVStopState    string `json:"sv_stop_state"`    // 电磁阀-关状态

	SVStartControlEV uint8 `json:"sv_start_control_ev"` // 电磁阀-开控制-有效值
	SVStopControlEV  uint8 `json:"sv_stop_control_ev"`  // 电磁阀-关控制-有效值
	SVStartStateEV   uint8 `json:"sv_start_state_ev"`   // 电磁阀-开状态-有效值
	SVStopStateEV    uint8 `json:"sv_stop_state_ev"`    // 电磁阀-关状态-有效值
	/*--- 以上全部都是选择的 AI~DQ ---*/

	Liansuo            string `json:"liansuo"` // 连锁 00
	LiansuoValue       uint8  `json:"liansuo_value"`
	ControlMethod      string `json:"control_method"` // 控制方法 02
	ControlMethodValue uint8  `json:"control_method_value"`
}

// PowerModel 电源模型
type PowerModel struct {
	PLCType uint8  `json:"plc_type"` // [1.西门子 2.AB 3.汇川 4.信捷 5.和利时 6.三菱 7.欧姆龙]
	IP      string `json:"ip"`       // IP地址
	Port    uint16 `json:"port"`     // 端口

	U1Type       uint8  `json:"u1_type"`        // 1.real 2.int8 3.int16 4.bool
	U1BlockValue uint16 `json:"u1_block_value"` // --- U1块
	U1AddrValue  string `json:"u1_addr_value"`  // --- U1地址
	U1Addr       string `json:"u1_addr"`        // --- U1绑定的第三方PLC变量地址

	U2Type       uint8  `json:"u2_type"`
	U2BlockValue uint16 `json:"u2_block_value"`
	U2AddrValue  string `json:"u2_addr_value"`
	U2Addr       string `json:"u2_addr"`

	U3Type       uint8  `json:"u3_type"`
	U3BlockValue uint16 `json:"u3_block_value"`
	U3AddrValue  string `json:"u3_addr_value"`
	U3Addr       string `json:"u3_addr"`

	I1Type       uint8  `json:"i1_type"`
	I1BlockValue uint16 `json:"i1_block_value"` // --- I1块
	I1AddrValue  string `json:"i1_addr_value"`  // --- I1值
	I1Addr       string `json:"i1_addr"`        // --- I1绑定的第三方PLC变量地址

	I2Type       uint8  `json:"i2_type"`
	I2BlockValue uint16 `json:"i2_block_value"`
	I2AddrValue  string `json:"i2_addr_value"`
	I2Addr       string `json:"i2_addr"`

	I3Type       uint8  `json:"i3_type"`
	I3BlockValue uint16 `json:"i3_block_value"`
	I3AddrValue  string `json:"i3_addr_value"`
	I3Addr       string `json:"i3_addr"`

	FType       uint8  `json:"f_type"`
	FBlockValue uint16 `json:"f_block_value"` // --- F块
	FAddrValue  string `json:"f_addr_value"`  // --- F值
	FAddr       string `json:"f_addr"`        // --- F绑定的第三方PLC变量地址

	ActivePowerType       uint8  `json:"active_power_type"`
	ActivePowerBlockValue uint16 `json:"active_power_block_value"` // 有功功率-块
	ActivePowerAddrValue  string `json:"active_power_addr_value"`  // 有功功率-值
	ActivePowerAddr       string `json:"active_power_addr"`        // 有功功率-绑定的第三方PLC变量地址

	ReactivePowerType       uint8  `json:"reactive_power_type"`
	ReactivePowerBlockValue uint16 `json:"reactive_power_block_value"` // 无功功率-块
	ReactivePowerAddrValue  string `json:"reactive_power_addr_value"`  // 无功功率-值
	ReactivePowerAddr       string `json:"reactive_power_addr"`        // 无功功率-绑定的第三方PLC变量地址

	ApparentPowerType       uint8  `json:"apparent_power_type"`
	ApparentPowerBlockValue uint16 `json:"apparent_power_block_value"` // 视在功率-值
	ApparentPowerAddrValue  string `json:"apparent_power_addr_value"`  // 视在功率-绑定的第三方PLC变量地址
	ApparentPowerAddr       string `json:"apparent_power_addr"`        // 视在功率-绑定的第三方PLC变量地址
	/*--- 以上全部都是自动生成的变量地址 ---*/
}

// PowerStateModel 电源模型
type PowerStateModel struct {
	PLCType uint8  `json:"plc_type"` // [1.西门子 2.AB 3.汇川 4.信捷 5.和利时 6.三菱 7.欧姆龙]
	IP      string `json:"ip"`       // IP地址
	Port    uint16 `json:"port"`     // 端口

	RunningStateType       uint8  `json:"running_state_type"`        //  1.real 2.int8 3.int16 4.bool
	RunningStateBlockValue uint16 `json:"running_state_block_value"` // 运行状态-块
	RunningStateAddrValue  string `json:"running_state_addr_value"`  // 运行状态-值
	RunningStateAddr       string `json:"running_state_addr"`        // 运行状态地址

	ErrorStateType       uint8  `json:"error_state_type"`
	ErrorStateBlockValue uint16 `json:"error_state_block_value"` // 故障状态-块
	ErrorStateAddrValue  string `json:"error_state_addr_value"`  // 故障状态-值
	ErrorStateAddr       string `json:"error_state_addr"`        // 故障状态地址
	/*--- 以上全部都是自动生成的变量地址 ---*/
}

// ModeCollectModel 模态采集
type ModeCollectModel struct {
	StimulatePoint string `json:"stimulate_point"` // 激励点位
	ResponsePoint  string `json:"response_point"`  // 响应点位

	StartControl string `json:"start_control"` // 开控制
	StopControl  string `json:"stop_control"`  // 关控制
	StartState   string `json:"start_state"`   // 开状态
	StopState    string `json:"stop_state"`    // 关状态

	StartControlEV uint8 `json:"start_control_ev"` // 开控制-有效值
	StopControlEV  uint8 `json:"stop_control_ev"`  // 关控制-有效值
	StartStateEV   uint8 `json:"start_state_ev"`   // 开状态-有效值
	StopStateEV    uint8 `json:"stop_state_ev"`    // 关状态-有效值

	/*--- 以上全部都是选择的 AI~DQ ---*/
}

// DiagModel 故障诊断
type DiagModel struct {
	DiagMode        string  `json:"diag_mode"`   // 诊断模式 00
	DiagParam1      string  `json:"diag_param1"` // 诊断参数1 01
	DiagParam2      string  `json:"diag_param2"` // 诊断参数2 02
	DiagParam3      string  `json:"diag_param3"` // 诊断参数3 03
	DiagParam4      string  `json:"diag_param4"` // 诊断参数4 04
	DiagParam5      string  `json:"diag_param5"` // 诊断参数5 05
	DiagModeValue   float64 `json:"diag_mode_value"`
	DiagParam1Value float64 `json:"diag_param1_value"`
	DiagParam2Value float64 `json:"diag_param2_value"`
	DiagParam3Value float64 `json:"diag_param3_value"`
	DiagParam4Value float64 `json:"diag_param4_value"`
	DiagParam5Value float64 `json:"diag_param5_value"`

	/*--- 以上全部都是自动生成的变量地址 ---*/
}

type CommandHistory struct {
	Id           int         `json:"id" gorm:"column:id"`
	Type         uint8       `json:"type" gorm:"column:type"`
	ProjectID    int         `json:"project_id" gorm:"column:project_id"`
	FSID         int         `json:"fs_id" gorm:"column:fs_id"`
	Name         string      `json:"name" gorm:"column:name"`
	Detail       string      `json:"detail" gorm:"column:detail"`
	Url          string      `json:"url" gorm:"column:url"`
	Params       string      `json:"params" gorm:"column:params"`
	ResultCode   int         `json:"result_code" gorm:"column:result_code"`
	ResultDetail string      `json:"result_detail" gorm:"column:result_detail"`
	CreateTime   string      `json:"create_time" gorm:"column:create_time"`
	FSInfo       FSEquipSlim `json:"fs_info" gorm:"foreignKey:FSID;references:ID"`
}

type DataScale struct {
	AI          uint8
	AQ          uint8
	DI          uint8
	DQ          uint8
	Other       uint8
	EData       uint16
	Bengzu      uint8
	Zengya      uint8
	Diantiao    uint8
	Pressure    uint8
	Power       uint8
	PowerState  uint8
	ModeCollect uint8
	Diag        uint8
}

func (d *CommandHistory) TableName() string {
	return "fs_command_history"
}

type UploadHistory struct {
	Id           int      `json:"id" gorm:"column:id"`
	ProjectID    int      `json:"project_id" gorm:"column:project_id"`
	FSID         int      `json:"fs_id" gorm:"column:fs_id"`
	ModuleType   string   `json:"module_type" gorm:"column:module_type"`
	ModuleNumber int      `json:"module_number" gorm:"column:module_number"`
	Data         string   `json:"data" gorm:"column:data"`
	Status       uint8    `json:"status" gorm:"column:status"`
	CreateTime   *string  `json:"create_time" gorm:"column:create_time"`
	UpdateTime   *string  `json:"update_time" gorm:"column:update_time"`
	ProjectInfo  *Project `json:"project_info" gorm:"foreignKey:ProjectID;references:ID"`
	FSEInfo      *FSEquip `json:"fse_info" gorm:"foreignKey:FSID;references:ID"`
}

func (t *UploadHistory) TableName() string {
	return "fs_upload_history"
}

func (t *UploadHistory) Insert() (err error) {
	now := tools.GetNow()
	t.CreateTime = &now
	t.UpdateTime = &now
	err = DB.Create(t).Error
	return err
}

func UploadHistoryHandleExecute(fse *FSEquip, info *UploadHistory) (list, extendList []*FrameItem, err error) {
	list = make([]*FrameItem, 0)
	extendList = make([]*FrameItem, 0)
	code2 := AllowFSCode2[info.ModuleType]
	code3 := fmt.Sprintf("%02d", info.ModuleNumber)
	now := tools.GetNow()
	switch info.ModuleType {
	case "AI":
		fallthrough
	case "AQ":
		err = json.Unmarshal([]byte(info.Data), &list)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) error {
			//fmt.Printf("删除旧fs_module和frame_item, fs_id=%d, code2=%s, code3=%s\n", info.FSID, code2, code3)
			err = tx.Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			moduleData := &FSModule{}
			moduleData.ProjectID = info.ProjectID
			moduleData.FSID = info.FSID
			moduleData.ModuleType = info.ModuleType
			moduleData.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			moduleData.Code1 = fse.Code1
			moduleData.Code2 = code2
			moduleData.Code3 = code3
			moduleData.CreateTime = &now
			moduleData.UpdateTime = &now
			err = tx.Create(moduleData).Error
			if err != nil {
				return err
			}

			for _, item := range list {
				item.ProjectID = fse.ProjectID
				item.Code4 = tools.SubStr(item.Addr, 9, 3)
				item.FSID = info.FSID
				item.ModuleID = moduleData.ID
				item.FieldName = "变量名 " + item.Addr
				item.SpecType = "float32"
				item.Endian = fse.FloatEndian
				item.RatioOperator = "*"
				item.Ratio = 1.0
				item.AlertVarAddr = item.Addr + ".alert"
				item.ShieldVarAddr = item.Addr + ".shield"
				item.Upper2LimitVarAddr = item.Addr + ".upper2"
				item.UpperLimitVarAddr = item.Addr + ".upper"
				item.LowerLimitVarAddr = item.Addr + ".lower"
				item.Lower2LimitVarAddr = item.Addr + ".lower2"
				item.Upper2LimitEnable = 1
				item.UpperLimitEnable = 1
				item.LowerLimitEnable = 1
				item.Lower2LimitEnable = 1
				item.CreateTime = &now
				item.UpdateTime = &now
			}
			err = tx.Create(&list).Error
			if err != nil {
				return err
			}
			for _, row := range list {
				upper2LimitValue := row.Upper2LimitValue
				upperLimitValue := row.UpperLimitValue
				lowerLimitValue := row.LowerLimitValue
				lower2LimitValue := row.Lower2LimitValue
				row.AlertVarAddr = ""
				row.ShieldVarAddr = ""

				row.Upper2LimitEnable = 0
				row.Upper2LimitVarAddr = ""
				row.Upper2LimitValue = 0

				row.UpperLimitEnable = 0
				row.UpperLimitVarAddr = ""
				row.UpperLimitValue = 0

				row.LowerLimitEnable = 0
				row.LowerLimitVarAddr = ""
				row.LowerLimitValue = 0

				row.Lower2LimitEnable = 0
				row.Lower2LimitVarAddr = ""
				row.Lower2LimitValue = 0
				// 上上限
				tmpUpper2 := *row
				tmpUpper2.PID = row.ID
				tmpUpper2.ID = 0
				tmpUpper2.IsInternal = 1
				tmpUpper2.SpecType = "float32"
				tmpUpper2.Addr = row.Addr + ".upper2"
				tmpUpper2.FieldName = row.Addr + ".上上限"
				tmpUpper2.Value = upper2LimitValue
				extendList = append(extendList, &tmpUpper2)
				// 上限
				tmpUpper := *row
				tmpUpper.PID = row.ID
				tmpUpper.ID = 0
				tmpUpper.IsInternal = 1
				tmpUpper.SpecType = "float32"
				tmpUpper.Addr = row.Addr + ".upper"
				tmpUpper.FieldName = row.Addr + ".上限"
				tmpUpper.Value = upperLimitValue
				extendList = append(extendList, &tmpUpper)
				// 下限
				tmpLower := *row
				tmpLower.PID = row.ID
				tmpLower.ID = 0
				tmpLower.IsInternal = 1
				tmpLower.SpecType = "float32"
				tmpLower.Addr = row.Addr + ".lower"
				tmpLower.FieldName = row.Addr + ".下限"
				tmpLower.Value = lowerLimitValue
				extendList = append(extendList, &tmpLower)
				// 下下限
				tmpLower2 := *row
				tmpLower2.PID = row.ID
				tmpLower2.ID = 0
				tmpLower2.IsInternal = 1
				tmpLower2.SpecType = "float32"
				tmpLower2.Addr = row.Addr + ".lower2"
				tmpLower2.FieldName = row.Addr + ".下下限"
				tmpLower2.Value = lower2LimitValue
				extendList = append(extendList, &tmpLower2)
				// 报警
				tmpAlert := *row
				tmpAlert.PID = row.ID
				tmpAlert.ID = 0
				tmpAlert.IsInternal = 1
				tmpAlert.SpecType = "uint8"
				tmpAlert.Addr = row.Addr + ".alert"
				tmpAlert.FieldName = row.Addr + ".报警"
				tmpAlert.Value = float64(row.AlertBit)
				extendList = append(extendList, &tmpAlert)
				// 屏蔽
				tmpShield := *row
				tmpShield.PID = row.ID
				tmpShield.ID = 0
				tmpShield.IsInternal = 1
				tmpShield.SpecType = "uint8"
				tmpShield.Addr = row.Addr + ".shield"
				tmpShield.FieldName = row.Addr + ".屏蔽"
				tmpShield.Value = float64(row.Shield)
				extendList = append(extendList, &tmpShield)

			}
			err = tx.Create(&extendList).Error
			if err != nil {
				return err
			}

			for _, row := range list {
				v, ok := VariablesMap.Get(row.Addr)
				if ok {
					*v = Variable{
						FrameItem: *row,
					}
				} else {
					VariablesMap.Set(row.Addr, &Variable{
						FrameItem: *row,
					})
				}
			}

			for _, row := range extendList {
				v, ok := VariablesMap.Get(row.Addr)
				if ok {
					*v = Variable{
						FrameItem: *row,
					}
				} else {
					VariablesMap.Set(row.Addr, &Variable{
						FrameItem: *row,
					})
				}
			}

			return nil
		})
	case "DI":
		fallthrough
	case "DQ":
		err = json.Unmarshal([]byte(info.Data), &list)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) error {
			err = tx.Model(&FSModule{}).
				Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).
				Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).
				Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).
				Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			moduleData := &FSModule{}
			moduleData.ProjectID = info.ProjectID
			moduleData.FSID = info.FSID
			moduleData.ModuleType = info.ModuleType
			moduleData.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			moduleData.Code1 = fse.Code1
			moduleData.Code2 = code2
			moduleData.Code3 = code3
			moduleData.CreateTime = &now
			moduleData.UpdateTime = &now
			err = tx.Create(moduleData).Error
			if err != nil {
				return err
			}
			for _, item := range list {
				item.ProjectID = fse.ProjectID
				item.Code4 = tools.SubStr(item.Addr, 9, 3)
				item.FSID = info.FSID
				item.ModuleID = moduleData.ID
				item.FieldName = "变量名 " + item.Addr
				item.SpecType = "uint8"
				item.Endian = fse.IntEndian
				item.RatioOperator = "*"
				item.Ratio = 1.0
				item.AlertVarAddr = item.Addr + ".alert"
				item.ShieldVarAddr = item.Addr + ".shield"
				item.CreateTime = &now
				item.UpdateTime = &now
			}
			err = tx.Create(&list).Error
			if err != nil {
				return err
			}
			for _, row := range list {
				row.AlertVarAddr = ""
				row.ShieldVarAddr = ""
				row.Upper2LimitVarAddr = ""
				row.UpperLimitVarAddr = ""
				row.LowerLimitVarAddr = ""
				row.Lower2LimitVarAddr = ""
				// 报警
				tmpAlert := *row
				tmpAlert.PID = row.ID
				tmpAlert.ID = 0
				tmpAlert.IsInternal = 1
				tmpAlert.SpecType = "uint8"
				tmpAlert.Addr = row.Addr + ".alert"
				tmpAlert.FieldName = row.Addr + ".报警"
				tmpAlert.Value = float64(row.AlertBit)
				extendList = append(extendList, &tmpAlert)
				// 屏蔽
				tmpShield := *row
				tmpShield.PID = row.ID
				tmpShield.ID = 0
				tmpShield.IsInternal = 1
				tmpShield.SpecType = "uint8"
				tmpShield.Addr = row.Addr + ".shield"
				tmpShield.FieldName = row.Addr + ".屏蔽"
				tmpShield.Value = float64(row.Shield)
				extendList = append(extendList, &tmpShield)

			}
			err = tx.Create(&extendList).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "Other":
		err = json.Unmarshal([]byte(info.Data), &list)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) error {
			err = tx.Model(&FSModule{}).
				Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).
				Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).
				Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).
				Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			moduleData := &FSModule{}
			moduleData.ProjectID = info.ProjectID
			moduleData.FSID = info.FSID
			moduleData.ModuleType = info.ModuleType
			moduleData.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			moduleData.Code1 = fse.Code1
			moduleData.Code2 = code2
			moduleData.Code3 = code3
			moduleData.CreateTime = &now
			moduleData.UpdateTime = &now
			err = tx.Create(moduleData).Error
			if err != nil {
				return err
			}
			for _, item := range list {
				item.ProjectID = fse.ProjectID
				item.Code4 = tools.SubStr(item.Addr, 9, 3)
				item.FSID = info.FSID
				item.ModuleID = moduleData.ID
				item.FieldName = "变量名 " + item.Addr
				if item.ChannelType == "AI" || item.ChannelType == "AQ" {
					item.SpecType = "float32"
					item.Endian = fse.FloatEndian
					item.AlertVarAddr = item.Addr + ".alert"
					item.ShieldVarAddr = item.Addr + ".shield"
					item.Upper2LimitVarAddr = item.Addr + ".upper2"
					item.UpperLimitVarAddr = item.Addr + ".upper"
					item.LowerLimitVarAddr = item.Addr + ".lower"
					item.Lower2LimitVarAddr = item.Addr + ".lower2"
					item.Upper2LimitEnable = 1
					item.UpperLimitEnable = 1
					item.LowerLimitEnable = 1
					item.Lower2LimitEnable = 1
				} else {
					item.SpecType = "uint8"
					item.Endian = fse.IntEndian
					item.AlertVarAddr = item.Addr + ".alert"
					item.ShieldVarAddr = item.Addr + ".shield"
				}
				item.RatioOperator = "*"
				item.Ratio = 1.0
				item.CreateTime = &now
				item.UpdateTime = &now
			}
			err = tx.Create(&list).Error
			if err != nil {
				return err
			}
			for _, row := range list {
				row.AlertVarAddr = ""
				row.ShieldVarAddr = ""

				row.Upper2LimitEnable = 0
				row.Upper2LimitVarAddr = ""
				row.Upper2LimitValue = 0

				row.UpperLimitVarAddr = ""
				row.UpperLimitEnable = 0
				row.UpperLimitValue = 0

				row.LowerLimitEnable = 0
				row.LowerLimitVarAddr = ""
				row.LowerLimitValue = 0

				row.Lower2LimitEnable = 0
				row.Lower2LimitVarAddr = ""
				row.Lower2LimitValue = 0

				if row.ChannelType == "AI" || row.ChannelType == "AQ" {
					// 上上限
					tmpUpper2 := *row
					tmpUpper2.PID = row.ID
					tmpUpper2.ID = 0
					tmpUpper2.IsInternal = 1
					tmpUpper2.SpecType = "float32"
					tmpUpper2.Addr = row.Addr + ".upper2"
					tmpUpper2.FieldName = row.Addr + ".上上限"
					tmpUpper2.Value = row.Upper2LimitValue
					extendList = append(extendList, &tmpUpper2)
					// 上限
					tmpUpper := *row
					tmpUpper.PID = row.ID
					tmpUpper.ID = 0
					tmpUpper.IsInternal = 1
					tmpUpper.SpecType = "float32"
					tmpUpper.Addr = row.Addr + ".upper"
					tmpUpper.FieldName = row.Addr + ".上限"
					tmpUpper.Value = row.UpperLimitValue
					extendList = append(extendList, &tmpUpper)
					// 下限
					tmpLower := *row
					tmpLower.PID = row.ID
					tmpLower.ID = 0
					tmpLower.IsInternal = 1
					tmpLower.SpecType = "float32"
					tmpLower.Addr = row.Addr + ".lower"
					tmpLower.FieldName = row.Addr + ".下限"
					tmpLower.Value = row.LowerLimitValue
					extendList = append(extendList, &tmpLower)
					// 下下限
					tmpLower2 := *row
					tmpLower2.PID = row.ID
					tmpLower2.ID = 0
					tmpLower2.IsInternal = 1
					tmpLower2.SpecType = "float32"
					tmpLower2.Addr = row.Addr + ".lower2"
					tmpLower2.FieldName = row.Addr + ".下下限"
					tmpLower2.Value = row.Lower2LimitValue
					extendList = append(extendList, &tmpLower2)
				}
				// 报警
				tmpAlert := *row
				tmpAlert.PID = row.ID
				tmpAlert.ID = 0
				tmpAlert.IsInternal = 1
				tmpAlert.SpecType = "uint8"
				tmpAlert.Addr = row.Addr + ".alert"
				tmpAlert.FieldName = row.Addr + ".报警"
				tmpAlert.Value = float64(row.AlertBit)
				extendList = append(extendList, &tmpAlert)
				// 屏蔽
				tmpShield := *row
				tmpShield.PID = row.ID
				tmpShield.ID = 0
				tmpShield.IsInternal = 1
				tmpShield.SpecType = "uint8"
				tmpShield.Addr = row.Addr + ".shield"
				tmpShield.FieldName = row.Addr + ".屏蔽"
				tmpShield.Value = float64(row.Shield)
				extendList = append(extendList, &tmpShield)

			}
			err = tx.Create(&extendList).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "泵组电磁阀":
		content := &BengzuModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			list, err = ValidateFSModelContent(fse.ProjectID, content)
			if err != nil {
				return
			}
			err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			if err != nil {
				return err
			}
			if len(list) > 0 {
				err = tx.Create(&list).Error
				if err != nil {
					return err
				}
			}
			FillFrameAddrToBengzuModel(list, content)
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "增压泵电磁阀":
		content := &ZengyaModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			list, err = ValidateFSModelContent(fse.ProjectID, content)
			if err != nil {
				return
			}
			err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			if err != nil {
				return err
			}
			if len(list) > 0 {
				err = tx.Create(&list).Error
				if err != nil {
					return err
				}
			}
			FillFrameAddrToZengyaModel(list, content)
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "电调阀":
		content := &DiantiaoSVModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			list, err = ValidateFSModelContent(fse.ProjectID, content)
			if err != nil {
				return
			}
			err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			if err != nil {
				return err
			}
			if len(list) > 0 {
				err = tx.Create(&list).Error
				if err != nil {
					return err
				}
			}
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "压力电磁阀":
		content := &PressureSVModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			list, err = ValidateFSModelContent(fse.ProjectID, content)
			if err != nil {
				return
			}
			err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			if err != nil {
				return err
			}
			if len(list) > 0 {
				err = tx.Create(&list).Error
				if err != nil {
					return err
				}
			}
			FillFrameAddrToPressureModel(list, content)
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "模态采集":
		content := &ModeCollectModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			list, err = ValidateFSModelContent(fse.ProjectID, content)
			if err != nil {
				return
			}
			err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			if err != nil {
				return err
			}
			if len(list) > 0 {
				err = tx.Create(&list).Error
				if err != nil {
					return err
				}
			}
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "故障诊断":
		content := &DiagModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			list, err = ValidateFSModelContent(fse.ProjectID, content)
			if err != nil {
				return
			}
			err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			if err != nil {
				return err
			}
			if len(list) > 0 {
				err = tx.Create(&list).Error
				if err != nil {
					return err
				}
			}
			FillFrameAddrToDiagModel(list, content)
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "电源控制":
		content := &PowerModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			//list, err = ValidateFSModelContent(fse.ProjectID, content)
			//if err != nil {
			//	return
			//}
			//err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			//if err != nil {
			//	return err
			//}
			//if len(list) > 0 {
			//	err = tx.Create(&list).Error
			//	if err != nil {
			//		return err
			//	}
			//}
			//FillFrameAddrToPowerModel(list, content)
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	case "电源状态":
		content := &PowerStateModel{}
		err = json.Unmarshal([]byte(info.Data), &content)
		if err != nil {
			err = errors.New(fmt.Sprintf("json解析失败: %v", err))
			return
		}
		err = DB.Transaction(func(tx *gorm.DB) (err error) {
			err = tx.Model(&FSModule{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FSModule{}).Error
			if err != nil {
				return err
			}
			err = tx.Model(&FrameItem{}).Where("fs_id = ? AND code2 = ? AND code3 = ?", info.FSID, code2, code3).Delete(&FrameItem{}).Error
			if err != nil {
				return err
			}
			data := &FSModule{}
			data.ProjectID = info.ProjectID
			data.FSID = info.FSID
			data.ModuleType = info.ModuleType
			data.ModuleName = fmt.Sprintf("%s%s", info.ModuleType, code3)
			data.Code1 = fse.Code1
			data.Code2 = code2
			data.Code3 = code3
			data.CreateTime = &now
			data.UpdateTime = &now
			err = tx.Create(data).Error
			if err != nil {
				return err
			}
			//list, err = ValidateFSModelContent(fse.ProjectID, content)
			//if err != nil {
			//	return
			//}
			//err = FSModelFrameItemHandle(list, data, fse.ProjectID)
			//if err != nil {
			//	return err
			//}
			//if len(list) > 0 {
			//	err = tx.Create(&list).Error
			//	if err != nil {
			//		return err
			//	}
			//}
			//FillFrameAddrToPowerStateModel(list, content)
			jsonB, _ := json.Marshal(content)
			data.JsonDetail = string(jsonB)
			err = tx.Model(&FSModule{}).Where("id = ?", data.ID).Update("json_detail", string(jsonB)).Error
			if err != nil {
				return err
			}
			return nil
		})
	default:
		err = errors.New(fmt.Sprintf("当前模块模型暂不支持覆盖: %s", info.ModuleType))
		return
	}
	return
}
func ValidateFSModuleContentCombo(projectID int, fsm *FSModule, content interface{}) (list []*FrameItem, err error) {
	list, err = ValidateFSModelContent(projectID, content) // 验证模型内容
	if err != nil {
		return
	}
	if len(list) == 0 {
		return
	}
	err = FSModelFrameItemHandle(list, fsm, projectID) // 待生成的变量字段补充
	if err != nil {
		return
	}
	err = DB.Create(&list).Error // 生成新变量
	if err != nil {
		return
	}
	return
}
func FSModelFrameItemHandle(list []*FrameItem, data *FSModule, projectID int) (err error) {
	if len(list) == 0 {
		return
	}
	now := tools.GetNow()
	usedCode4 := make([]string, 0)
	err = DB.Model(&FrameItem{}).Where("project_id = ? AND code1 = ? AND code2 = ? AND code3 = ?", projectID, data.Code1, data.Code2, data.Code3).Pluck("code4", &usedCode4).Error
	if err != nil {
		return err
	}
	availableCode4 := GetAvailableCode(AllCode4FS(), usedCode4)
	if len(availableCode4) < len(list) {
		err = errors.New("当前模型下的变量地址已满 code4")
		return
	}
	for i, item := range list {
		item.ProjectID = projectID
		item.Code1 = data.Code1
		item.Code2 = data.Code2
		item.Code3 = data.Code3
		item.FSID = data.FSID
		item.ModuleID = data.ID
		item.ChannelType = data.ModuleType
		item.RatioOperator = "*"
		item.Ratio = 1.0
		item.CreateTime = &now
		item.UpdateTime = &now

		item.Code4 = availableCode4[i]
		item.Addr = fmt.Sprintf("%s-%s-%s-%s", item.Code1, item.Code2, item.Code3, item.Code4)
	}
	return
}

/*
验证FS模型内容, 并生成需要生成变量的列表
1. 设置的变量地址有就验证 listToBeValidated
2. 没有就自动生成 listToBeInserted
*/
func ValidateFSModelContent(projectID int, content interface{}) (listToBeInserted []*FrameItem, err error) {
	listToBeInserted = make([]*FrameItem, 0)   // 待生成的变量列表
	listToBeValidated := make([]*FrameItem, 0) // 待验证的变量列表
	switch content.(type) {
	case *BengzuModel:
		data, _ := content.(*BengzuModel)
		list := []*fieldCheckList{
			{"泵前电磁阀-启动控制", data.BengqianStartControl, "DQ"},
			{"泵前电磁阀-停止控制", data.BengqianStopControl, "DQ"},
			{"泵前电磁阀-启动状态", data.BengqianStartState, "DI"},
			{"泵前电磁阀-停止状态", data.BengqianStopState, "DI"},

			{"前级泵-启动控制", data.QianjibengStartControl, "DQ"},
			{"前级泵-停止控制", data.QianjibengStopControl, "DQ"},
			{"前级泵-启动状态", data.QianjibengStartState, "DI"},
			{"前级泵-停止状态", data.QianjibengStopState, "DI"},

			{"罗茨泵-启动控制", data.LuocibengStartControl, "DQ"},
			{"罗茨泵-停止控制", data.LuocibengStopControl, "DQ"},
			{"罗茨泵-启动状态", data.LuocibengStartState, "DI"},
			{"罗茨泵-停止状态", data.LuocibengStopState, "DI"},

			{"泵前压力", data.BengqianPressure, "AI"},
			{"远程就地", data.RemoteLocal, "DI"},
		}
		err = checkAddrModuleType(list)
		if err != nil {
			return
		}
		if data.BengzuStartControl == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-启动控制", Addr: data.BengzuStartControl, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-启动控制", Addr: data.BengzuStartControl, SpecType: "uint8"})
		}
		if data.BengzuStopControl == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-停止控制", Addr: data.BengzuStopControl, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-停止控制", Addr: data.BengzuStopControl, SpecType: "uint8"})
		}
		if data.BengzuStartState == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-启动状态", Addr: data.BengzuStartState, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-启动状态", Addr: data.BengzuStartState, SpecType: "uint8"})
		}
		if data.BengzuStopState == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-停止状态", Addr: data.BengzuStopState, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-停止状态", Addr: data.BengzuStopState, SpecType: "uint8"})
		}
		if data.BengzuParam1 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-参数1", Addr: data.BengzuParam1, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-参数1", Addr: data.BengzuParam1, SpecType: "float32"})
		}
		if data.BengzuParam2 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-参数2", Addr: data.BengzuParam2, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-参数2", Addr: data.BengzuParam2, SpecType: "float32"})
		}
		if data.BengzuParam3 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-参数3", Addr: data.BengzuParam3, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-参数3", Addr: data.BengzuParam3, SpecType: "float32"})
		}
		if data.BengzuParam4 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-参数4", Addr: data.BengzuParam4, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-参数4", Addr: data.BengzuParam4, SpecType: "float32"})
		}
		if data.BengzuParam5 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-参数5", Addr: data.BengzuParam5, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-参数5", Addr: data.BengzuParam5, SpecType: "float32"})
		}
		if data.Liansuo == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-连锁", Addr: data.Liansuo, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-连锁", Addr: data.Liansuo, SpecType: "uint8"})
		}
		//if data.RemoteLocal == "" {
		//	listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-远程就地", Addr: data.RemoteLocal, SpecType: "uint8"})
		//} else {
		//	listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-远程就地", Addr: data.RemoteLocal, SpecType: "uint8"})
		//}
		if data.ControlMethod == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "泵组控制-控制方法", Addr: data.ControlMethod, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "泵组控制-控制方法", Addr: data.ControlMethod, SpecType: "uint8"})
		}
	case *ZengyaModel:
		data, _ := content.(*ZengyaModel)

		list := []*fieldCheckList{
			{"泵前电磁阀-启动控制", data.BengqianStartControl, "DQ"},
			{"泵前电磁阀-停止控制", data.BengqianStopControl, "DQ"},
			{"泵前电磁阀-启动状态", data.BengqianStartState, "DI"},
			{"泵前电磁阀-停止状态", data.BengqianStopState, "DI"},
			{"增压泵-启动控制", data.ZengyaStartControl, "DQ"},
			{"增压泵-停止控制", data.ZengyaStopControl, "DQ"},
			{"增压泵-启动状态", data.ZengyaStartState, "DI"},
			{"增压泵-停止状态", data.ZengyaStopState, "DI"},
			{"泵前压力", data.BengqianPressure, "AI"},
			{"远程就地", data.RemoteLocal, "DI"},
		}
		err = checkAddrModuleType(list)
		if err != nil {
			return
		}
		if data.Liansuo == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "连锁", Addr: data.Liansuo, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "连锁", Addr: data.Liansuo, SpecType: "uint8"})
		}
		//if data.RemoteLocal == "" {
		//	listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "远程就地", Addr: data.RemoteLocal, SpecType: "uint8"})
		//} else {
		//	listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "远程就地", Addr: data.RemoteLocal, SpecType: "uint8"})
		//}
		if data.ControlMethod == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "控制方法", Addr: data.ControlMethod, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "控制方法", Addr: data.ControlMethod, SpecType: "uint8"})
		}
	case *DiantiaoSVModel:
		data, _ := content.(*DiantiaoSVModel)

		list := []*fieldCheckList{
			{"当前开度", data.CurrentKaidu, "AI"},
			{"设置开度", data.SetKaidu, "AQ"},
			{"控制", data.Control, "DQ"},
			{"设置步长", data.SetStep, "AQ"},
			{"自检控制", data.SelfInspection, "DQ"},
			{"上调", data.Up, "DQ"},
			{"下调", data.Down, "DQ"},
			{"全开", data.AllOn, "DQ"},
			{"全关", data.AllOff, "DQ"},

			{"全开状态", data.AllOnState, "DI"},
			{"全关状态", data.AllOffState, "DI"},
			{"前级压力", data.QianjiPressure, "AI"},
			{"后级压力", data.HoujiPressure, "AI"},
			{"目标压力", data.DestPressure, "AQ"},
			{"P", data.P, "AQ"},
			{"I", data.I, "AQ"},
			{"D", data.D, "AQ"},
			{"自整定-启动控制", data.CustomStartControl, "DQ"},
			{"自整定-停止控制", data.CustomStopControl, "DQ"},
			{"自整定-启动状态", data.CustomStartState, "DI"},
			{"自整定-停止状态", data.CustomStopState, "DI"},
			{"PID", data.PID, "DQ"},
			{"远程就地", data.RemoteLocal, "DQ"},
			{"控制方法", data.ControlMethod, "AQ"},
		}
		err = checkAddrModuleType(list)
		if err != nil {
			return
		}
	case *PressureSVModel:
		data, _ := content.(*PressureSVModel)

		list := []*fieldCheckList{
			{"压力测点", data.Pressure, "AI"},
			{"电磁阀-开控制", data.SVStartControl, "DQ"},
			{"电磁阀-关控制", data.SVStopControl, "DQ"},
			{"电磁阀-开状态", data.SVStartState, "DI"},
			{"电磁阀-关状态", data.SVStopState, "DI"},
		}
		err = checkAddrModuleType(list)
		if err != nil {
			return
		}
		if data.Liansuo == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "连锁", Addr: data.Liansuo, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "连锁", Addr: data.Liansuo, SpecType: "uint8"})
		}
		if data.Liansuo == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "控制方法", Addr: data.ControlMethod, SpecType: "uint8"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "控制方法", Addr: data.ControlMethod, SpecType: "uint8"})
		}
	case *PowerModel:
		data, _ := content.(*PowerModel)
		if _, ok := AllowPLCType[data.PLCType]; !ok {
			err = errors.New("无效的PLC类型")
			return
		}
		if !tools.IsValidIP(data.IP) {
			err = errors.New("无效的ip")
			return
		}
		// ---  todo todo ,如果变量地址不为空则验证此PLC块地址是否存在此变量
		//plc, _ := FindPlcByIPAndPort(projectID, data.PLCType, data.IP, data.Port)
		//if plc.ID == 0 {
		//	err = errors.New("未找到当前IP端口对应的PLC设备")
		//	return
		//}
		//if !IsPointInPLC(plc, data.U1BlockValue, data.U1AddrValue) {
		//	err = errors.New("未在PLC设备中找到U1的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.U2BlockValue, data.U2AddrValue) {
		//	err = errors.New("未在PLC设备中找到U2的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.U3BlockValue, data.U3AddrValue) {
		//	err = errors.New("未在PLC设备中找到U3的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.I1BlockValue, data.I1AddrValue) {
		//	err = errors.New("未在PLC设备中找到I1的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.I2BlockValue, data.I2AddrValue) {
		//	err = errors.New("未在PLC设备中找到I2的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.I3BlockValue, data.I3AddrValue) {
		//	err = errors.New("未在PLC设备中找到I3的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.FBlockValue, data.FAddrValue) {
		//	err = errors.New("未在PLC设备中找到F的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.ActivePowerBlockValue, data.ActivePowerAddrValue) {
		//	err = errors.New("未在PLC设备中找到有功功率的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.ReactivePowerBlockValue, data.ReactivePowerAddrValue) {
		//	err = errors.New("未在PLC设备中找到无功功率的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.ApparentPowerBlockValue, data.ApparentPowerAddrValue) {
		//	err = errors.New("未在PLC设备中找到视在功率的块地址")
		//	return
		//}
	case *PowerStateModel:
		data, _ := content.(*PowerStateModel)
		if _, ok := AllowPLCType[data.PLCType]; !ok {
			err = errors.New("无效的PLC类型")
			return
		}
		if !tools.IsValidIP(data.IP) {
			err = errors.New("无效的ip")
			return
		}
		// ---  todo todo ,如果变量地址不为空则验证此PLC块地址是否存在此变量
		//plc, _ := FindPlcByIPAndPort(projectID, data.PLCType, data.IP, data.Port)
		//if plc.ID == 0 {
		//	err = errors.New("未找到当前IP端口对应的PLC设备")
		//	return
		//}
		//if !IsPointInPLC(plc, data.RunningStateBlockValue, data.RunningStateAddrValue) {
		//	err = errors.New("未在PLC设备中找到运行状态的块地址")
		//	return
		//}
		//if !IsPointInPLC(plc, data.ErrorStateBlockValue, data.ErrorStateAddrValue) {
		//	err = errors.New("未在PLC设备中找到故障状态的块地址")
		//	return
		//}
	case *ModeCollectModel:
		data, _ := content.(*ModeCollectModel)
		list := []*fieldCheckList{
			{"激励点位", data.StimulatePoint, "AI"},
			{"响应点位", data.ResponsePoint, "AI"},
			{"开控制", data.StartControl, "DQ"},
			{"关控制", data.StopControl, "DQ"},
			{"开状态", data.StartState, "DI"},
			{"关状态", data.StopState, "DI"},
		}
		err = checkAddrModuleType(list)
		if err != nil {
			return
		}
	case *DiagModel:
		data, _ := content.(*DiagModel)
		if data.DiagMode == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "诊断模式", Addr: data.DiagMode, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "诊断模式", Addr: data.DiagMode, SpecType: "float32"})
		}
		if data.DiagParam1 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "诊断参数1", Addr: data.DiagParam1, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "诊断参数1", Addr: data.DiagParam1, SpecType: "float32"})
		}
		if data.DiagParam2 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "诊断参数2", Addr: data.DiagParam2, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "诊断参数2", Addr: data.DiagParam2, SpecType: "float32"})
		}
		if data.DiagParam3 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "诊断参数3", Addr: data.DiagParam3, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "诊断参数3", Addr: data.DiagParam3, SpecType: "float32"})
		}
		if data.DiagParam4 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "诊断参数4", Addr: data.DiagParam4, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "诊断参数4", Addr: data.DiagParam4, SpecType: "float32"})
		}
		if data.DiagParam5 == "" {
			listToBeInserted = append(listToBeInserted, &FrameItem{FieldName: "诊断参数5", Addr: data.DiagParam5, SpecType: "float32"})
		} else {
			listToBeValidated = append(listToBeValidated, &FrameItem{FieldName: "诊断参数5", Addr: data.DiagParam5, SpecType: "float32"})
		}
	default:
		err = errors.New("未知的模块类型")
		return
	}
	if len(listToBeValidated) > 0 {
		err = checkAddrsSpecType(projectID, listToBeValidated)
		if err != nil {
			return
		}
	}
	return
}

type fieldCheckList struct {
	FieldName  string // 字段名称
	Addr       string // 变量地址
	ModuleType string // 应属于的模块类型
}

func matchAddr(str string) bool {
	pattern := `^\d{2}-\d{2}-\d{2}-\d{3}$`
	re := regexp.MustCompile(pattern)
	return re.MatchString(str)
}
func checkAddrModuleType(list []*fieldCheckList) (err error) {
	for _, row := range list {
		if row.Addr == "" {
			return errors.New("变量地址不能为空: " + row.FieldName)
		}
		if !matchAddr(row.Addr) {
			return errors.New("变量地址格式不正确: " + row.Addr)
		}
		codeArr := strings.Split(row.Addr, "-")
		code1Value, _ := strconv.Atoi(codeArr[0])
		if code1Value > 50 {
			return errors.New("必须选择FS自研设备的通道变量: " + row.FieldName)
		}
		switch codeArr[1] {
		case "00":
			if row.ModuleType != "AI" {
				return errors.New("必须选择AI模块的通道地址: " + row.FieldName)
			}
		case "01":
			if row.ModuleType != "AQ" {
				return errors.New("必须选择AQ模块的通道地址: " + row.FieldName)
			}
		case "02":
			if row.ModuleType != "DI" {
				return errors.New("必须选择DI模块的通道地址: " + row.FieldName)
			}
		case "03":
			if row.ModuleType != "DQ" {
				return errors.New("必须选择DQ模块的通道地址: " + row.FieldName)
			}
		case "04":
			return errors.New("暂不支持 other类型中的AI~DQ: " + row.FieldName)
		default:
			return errors.New("code2 格式不正确: " + row.Addr)
		}
	}
	return nil
}

func FillFrameAddrToBengzuModel(list []*FrameItem, content *BengzuModel) {
	for _, row := range list {
		switch row.FieldName {
		case "泵组控制-启动控制":
			content.BengzuStartControl = row.Addr
		case "泵组控制-停止控制":
			content.BengzuStopControl = row.Addr
		case "泵组控制-启动状态":
			content.BengzuStartState = row.Addr
		case "泵组控制-停止状态":
			content.BengzuStopState = row.Addr
		case "泵组控制-参数1":
			content.BengzuParam1 = row.Addr
		case "泵组控制-参数2":
			content.BengzuParam2 = row.Addr
		case "泵组控制-参数3":
			content.BengzuParam3 = row.Addr
		case "泵组控制-参数4":
			content.BengzuParam4 = row.Addr
		case "泵组控制-参数5":
			content.BengzuParam5 = row.Addr
		case "泵组控制-连锁":
			content.Liansuo = row.Addr
		//case "泵组控制-远程就地":
		//	content.RemoteLocal = row.Addr
		case "泵组控制-控制方法":
			content.ControlMethod = row.Addr
		}
	}
}
func FillFrameAddrToZengyaModel(list []*FrameItem, content *ZengyaModel) {
	for _, row := range list {
		switch row.FieldName {
		case "连锁":
			content.Liansuo = row.Addr
		//case "远程就地":
		//	content.RemoteLocal = row.Addr
		case "控制方法":
			content.ControlMethod = row.Addr
		}
	}
}
func FillFrameAddrToPressureModel(list []*FrameItem, content *PressureSVModel) {
	for _, row := range list {
		switch row.FieldName {
		case "连锁":
			content.Liansuo = row.Addr
		case "控制方法":
			content.ControlMethod = row.Addr
		}
	}
}
func FillFrameAddrToPowerModel(list []*FrameItem, content *PowerModel) {
	for _, row := range list {
		switch row.FieldName {
		case "U1块":
		case "U1地址":
			content.U1Addr = row.Addr
		case "U2块":
		case "U2地址":
			content.U2Addr = row.Addr
		case "U3块":
		case "U3地址":
			content.U3Addr = row.Addr
		case "I1块":
		case "I1地址":
			content.I1Addr = row.Addr
		case "I2块":
		case "I2地址":
			content.I2Addr = row.Addr
		case "I3块":
		case "I3地址":
			content.I3Addr = row.Addr
		case "F块":
		case "F地址":
			content.FAddr = row.Addr
		case "有功功率块":
		case "有功功率地址":
			content.ActivePowerAddr = row.Addr
		case "无功功率块":
		case "无功功率地址":
			content.ReactivePowerAddr = row.Addr
		case "视在功率块":
		case "视在功率地址":
			content.ApparentPowerAddr = row.Addr
		}
	}
}

func FillFrameAddrToPowerStateModel(list []*FrameItem, content *PowerStateModel) {
	for _, row := range list {
		switch row.FieldName {
		case "运行状态块":
		case "运行状态地址":
		case "故障状态块":
		case "故障状态地址":
		}
	}
}
func FillFrameAddrToDiagModel(list []*FrameItem, content *DiagModel) {
	for _, row := range list {
		switch row.FieldName {
		case "诊断模式":
			content.DiagMode = row.Addr
		case "诊断参数1":
			content.DiagParam1 = row.Addr
		case "诊断参数2":
			content.DiagParam2 = row.Addr
		case "诊断参数3":
			content.DiagParam3 = row.Addr
		case "诊断参数4":
			content.DiagParam4 = row.Addr
		case "诊断参数5":
			content.DiagParam5 = row.Addr
		}
	}
}

// FS模型变量对比数据类型
func checkAddrsSpecType(projectID int, list []*FrameItem) (err error) {
	if len(list) == 0 {
		return
	}
	addrs := make([]string, 0)
	for _, row := range list {
		addrs = append(addrs, row.Addr)
	}
	resultList := make([]*FrameItem, 0)
	err = DB.Where("project_id = ? AND addr in ?", projectID, addrs).
		Select("id", "addr", "spec_type").Find(&resultList).Error
	if err != nil {
		return errors.New(fmt.Sprintf("校验变量数据类型失败 checkAddrsSpecType error: %v", err.Error()))
	}
	for _, row := range list {
		matched := false
		for _, old := range resultList {
			if row.Addr == old.Addr {
				matched = true
				if row.SpecType != old.SpecType {
					err = errors.New(fmt.Sprintf("字段%s 与变量地址 %s 数据类型不匹配", row.FieldName, row.Addr))
					return
				}
			}
		}
		if !matched {
			err = errors.New(fmt.Sprintf("字段%s 变量地址不存在: %s", row.FieldName, row.Addr))
		}
	}
	return
}

// IsPointInPLC 判断PLC中是否存在此变量点位(块、地址)
func IsPointInPLC(plc *PPEExtPLC, db uint16, addrValue string) (exist bool) {
	mode := ""
	if plc.DataConfig.Type == "汇川" {
		mode = "modbus"
	}
	addrInt, addrFloat, _ := tools.AddrSplit(addrValue, mode)
	//fmt.Printf(">>> To find db=%d, addrInt=%d, addrFloat=%d\n", db, addrInt, addrFloat)
	for _, frame := range plc.FrameList {
		_ = json.Unmarshal([]byte(frame.JsonDetail), &frame.FrameItemParam)
		baseAddr := frame.StartAddr
		for _, row := range frame.FrameItemParam {
			//fmt.Printf("db=%d, addrInt=%d, addrFloat=%d\n", frame.DBNumber, baseAddr+uint16(row.Start), row.BoolBits)
			if uint16(frame.DBNumber) == db && (baseAddr+uint16(row.Start)) == addrInt && addrFloat == row.BoolBits {
				return true
			}
		}
	}
	return
}
func FindPlcByIPAndPort(projectID int, plcType uint8, ip string, port uint16) (plc *PPEExtPLC, err error) {
	listAll := make([]*PPEExtPLC, 0)
	err = DB.Preload("FrameList").Where("project_id = ? AND protocol_name = ?", projectID, "PLC").Find(&listAll).Error
	plc = &PPEExtPLC{}
	for _, row := range listAll {
		config := PLCConfig{}
		err2 := json.Unmarshal([]byte(row.Config), &config)
		if err2 != nil {
			j_log.LogWarning([]interface{}{fmt.Sprintf("plc json解析失败: ppe_id=%d, %s", row.ID, err2.Error())})
			continue
		}
		row.DataConfig = config
		rt := AllowPLCTypeModel[config.Type]
		if config.IP == ip && uint16(config.Port) == port && plcType == rt {
			plc = row
			return
		}
	}
	return
}
